package booter

import (
	"context"
	"fmt"
	"gitee.com/go-mid/booter/bootservice"
	"gitee.com/go-mid/booter/server"
	"gitee.com/go-mid/infra/xconfig/xviper"
	core "gitee.com/go-mid/infra/xcore"
	"gitee.com/go-mid/infra/xlog"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

var GlobalServer server.Server

type EnumCfgType string

const (
	CfgType_YAML EnumCfgType = "yaml"
	CfgType_ETCD EnumCfgType = "etcd"
)

type Boot struct {
	services               map[string]bootservice.Service
	preServiceDriverFuncs  []func(ctx context.Context, server server.Server) error
	postServiceDriverFuncs []func(ctx context.Context, server server.Server) error
	bootConf               server.BootConfig
	sbase                  server.Server
}

var defaultBoot = NewBoot()

//bootconf 优先级高于命令行
func Run(bootConf *server.BootConfig) error {
	return defaultBoot.mergerConfig(bootConf).Run()
}

func InitTest(bootConf *server.BootConfig) error {
	bootConf.IsTest = true
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		AppendPostServiceDriverFuncs(func(ctx context.Context, sb server.Server) error {
			wg.Done()
			return nil
		})
		err := Run(bootConf)
		if err != nil {
			fmt.Printf("################## err:%v\n", err)
		}
	}()
	wg.Wait()
	time.Sleep(time.Second)
	fmt.Println("-----------------------------  INIT OK  -----------------------------")
	return nil
}

//额外增加一些启动服务
func AppendService(services map[string]bootservice.Service) {
	defaultBoot.AppendService(services)
	return
}

//额外增加 前置初始化函数
func AppendPreServiceDriverFuncs(initfns ...func(ctx context.Context, server server.Server) error) {
	defaultBoot.AppendPreServiceDriverFuncs(initfns...)
	return
}

//额外增加 后置初始化函数
func AppendPostServiceDriverFuncs(initfns ...func(ctx context.Context, server server.Server) error) {
	defaultBoot.AppendPostServiceDriverFuncs(initfns...)
	return
}
func NewBoot() *Boot {
	boot := &Boot{
		services:               make(map[string]bootservice.Service),
		preServiceDriverFuncs:  make([]func(ctx context.Context, server server.Server) error, 0),
		postServiceDriverFuncs: make([]func(ctx context.Context, server server.Server) error, 0),
	}
	return boot
}
func (m *Boot) initConfig() {
	m.parseFlag()
}

func (m *Boot) mergerConfig(highPriority *server.BootConfig) *Boot {
	m.initConfig()
	if highPriority == nil {
		return m
	}
	if highPriority.Sname != "" {
		m.bootConf.Sname = highPriority.Sname
	}
	if highPriority.Cfgtype != "" {
		m.bootConf.Cfgtype = highPriority.Cfgtype
	}
	if highPriority.Cfgroot != "" {
		m.bootConf.Cfgroot = highPriority.Cfgroot
	}
	if highPriority.CfgSrc != "" {
		m.bootConf.CfgSrc = highPriority.CfgSrc
	}
	if len(highPriority.Addrs) > 0 {
		m.bootConf.Addrs = highPriority.Addrs
	}
	return m
}

//参数优先级，高到低
//程序直接输入
//显式调用 viper.Set
//命令行参数
//环境变量
//配置文件
//默认值
const (
	param_key_sname   = "sname"
	param_key_cfgsrc  = "cfgsrc"
	param_key_cfgtype = "cfgtype"
	param_key_cfgroot = "cfgroot"
	param_key_addrs   = "addrs"
)

func (m *Boot) parseFlag() {

	pflag.String(param_key_sname, "", "sname name")
	pflag.String(param_key_cfgsrc, "", "cfgsrc: file, etcd ,etcd3")
	pflag.String(param_key_cfgtype, "", "cfgtype: yaml, etcd ")
	pflag.String(param_key_cfgroot, "", "cfgroot: defautl /opt/conf ")
	pflag.String(param_key_addrs, "", "addrs: etcd地址信息使用,隔开 ")
	pflag.Parse()
	// 将 pflag 绑定到 viper
	viper.BindPFlags(pflag.CommandLine)
	// 设置环境变量前缀
	// 环境变量使用"mid_参数名"的格式设置
	viper.SetEnvPrefix("mid")
	// 自动从环境变量中读取配置
	viper.AutomaticEnv()
	viper.SetDefault(param_key_cfgsrc, "file")
	viper.SetDefault(param_key_cfgtype, "yaml")
	viper.SetDefault(param_key_cfgroot, "/opt/conf")

	sname := viper.GetString(param_key_sname)
	cfgsrc := viper.GetString(param_key_cfgsrc)
	cfgtype := viper.GetString(param_key_cfgtype)
	cfgroot := viper.GetString(param_key_cfgroot)
	addrs := core.SplitAndTrim(context.Background(), viper.GetString(param_key_addrs), ",", true)
	m.bootConf = server.BootConfig{
		Sname:   sname,
		CfgSrc:  xviper.ConfigSourceType(cfgsrc),
		Cfgtype: xviper.ConfigType(cfgtype),
		Cfgroot: cfgroot,
		Addrs:   addrs,
	}

}
func (m *Boot) AppendService(services map[string]bootservice.Service) *Boot {
	for k, v := range services {
		m.services[k] = v
	}
	return m
}
func (m *Boot) AppendPreServiceDriverFuncs(initfns ...func(ctx context.Context, server server.Server) error) *Boot {
	m.preServiceDriverFuncs = append(m.preServiceDriverFuncs, initfns...)
	return m
}
func (m *Boot) AppendPostServiceDriverFuncs(initfns ...func(ctx context.Context, server server.Server) error) *Boot {
	m.postServiceDriverFuncs = append(m.postServiceDriverFuncs, initfns...)
	return m
}
func (m *Boot) Run() error {
	fun := "Boot.Run -->"

	if err := m.initServer(); err != nil {
		return err
	}
	xlog.Infof(context.Background(), "%s awaiting signal", fun)
	m.awaitSignal()
	return nil
}
func (m *Boot) initServer() error {
	//fun:="Boot.initServer -->"
	ctx := context.Background()
	switch m.bootConf.CfgSrc {
	case xviper.FILE:
		yamlServer := server.NewViperServer(m.bootConf)
		yamlServer.AppendService(m.services)
		yamlServer.AppendPreServiceDriverFuncs(m.preServiceDriverFuncs)
		yamlServer.AppendPostServiceDriverFuncs(m.postServiceDriverFuncs)
		m.sbase = yamlServer
	case xviper.ETCD:
	default:
		return fmt.Errorf("unsupport config type: %s", m.bootConf.Cfgtype)
	}
	GlobalServer = m.sbase
	//服务启动
	if err := m.sbase.Startup(ctx); err != nil {
		return err
	}
	return nil
}

func (m *Boot) awaitSignal() {
	c := make(chan os.Signal, 1)
	ctx := context.Background()
	signals := []os.Signal{syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGPIPE}
	signal.Notify(c, signals...)

	for {
		select {
		case s := <-c:
			xlog.Infof(ctx, "receive a signal:%s", s.String())
			if s.String() == syscall.SIGTERM.String() {
				xlog.Infof(ctx, "receive a signal: %s, stop server", s.String())
				m.sbase.Shutdown(ctx)
				<-(chan int)(nil)
			}
		}
	}

}
